package com.pirestupppai.widgets.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.pirestupppai.R;
import com.pirestupppai.utils.Utils;
import com.pirestupppai.utils.WeakReferenceHandler;


/**
 * 自定义环形进度条
 * 可设置长按递增
 *
 * 部分参考 http://blog.csdn.net/xiaanming/article/details/10298163
 *
 * @author: xiaoluo
 * @date: 2017-01-18 10:03
 */
public class CircleProgressBar extends View implements Handler.Callback{
    private static final int MSG_UP = 110;
    private static final int MSG_CANCEL = 120;
    private static final int MSG_DOWN = 130;
    private Context mContext;

    private Paint mPaint;               // 画笔
    private int mCircleColor;           // 圆形初始颜色,默认灰色
    private int mCircleProgressColor;   // 圆环进度颜色,默认黑色
    private float mCircleWidth;         // 圆环宽度,默认5像素
    private int mTextColor;             // 中间字体颜色
    private float mTextSize;            // 中间字体大小
    private int mMaxProgress;           // 最大进度
    private int mProgress;              // 当前进度
    private int mMaxTime = 10 * 1000;   // 最大时间
    private boolean isShowText;         // 是否显示中间文字

    private int mStyle;                 // 样式
    public static final int STROKE = 0; // 空心
    public static final int FILL = 1;   // 实心
    private boolean canPress = false;   // 是否可以长按
    private boolean canPause = false;   // 长按操作是否支持暂停

    private TimeThread mTimeThread;     // 计时线程
    private boolean isPressing = false; // 是否长按
    private boolean isPause = false;    // 是否暂停
    private boolean isDelay = false;    // 是否延时计时
    private int mSleepTime = 200;       // 刷新间隔

    private OnTouchEventListener mListener;
    private WeakReferenceHandler mHandler = new WeakReferenceHandler(this);

    public CircleProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);

    }

    private void init(Context context, AttributeSet attrs) {
        mContext = context;
        mPaint = new Paint();

        // 获取自定义属性
        TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
        mCircleColor = typedArray.getColor(R.styleable.CircleProgressBar_circle_color, getResources().getColor(R.color.gray));
        mCircleProgressColor = typedArray.getColor(R.styleable.CircleProgressBar_circle_progress_color, getResources().getColor(R.color.black));
        mCircleWidth = typedArray.getDimension(R.styleable.CircleProgressBar_circle_width, getResources().getDimension(R.dimen.round_width));
        mTextColor = typedArray.getColor(R.styleable.CircleProgressBar_text_color, getResources().getColor(R.color.black));
        mTextSize = typedArray.getDimension(R.styleable.CircleProgressBar_text_size, getResources().getDimension(R.dimen.title_size));
        mMaxProgress = typedArray.getInteger(R.styleable.CircleProgressBar_max_progress, 100);
        isShowText = typedArray.getBoolean(R.styleable.CircleProgressBar_show_text, true);
        mStyle = typedArray.getInt(R.styleable.CircleProgressBar_style, 0);

        typedArray.recycle();
    }

    /**
     *  长按递增
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (!canPress) {
            return super.dispatchTouchEvent(event);
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mHandler.sendEmptyMessage(MSG_DOWN);
                break;
            case MotionEvent.ACTION_UP:
                mHandler.sendEmptyMessage(MSG_UP);
                break;
            case MotionEvent.ACTION_CANCEL:
                mHandler.sendEmptyMessage(MSG_CANCEL);
                break;
        }
        return true;
    }

    @Override
    public void setOnTouchListener(OnTouchListener l) {
        super.setOnTouchListener(l);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int centreX = getWidth() / 2;                    // 圆心X坐标
        int radius = (int) (centreX - mCircleWidth / 2);  // 圆环半径

        // 画最外层大圆环
        mPaint.setColor(mCircleColor);          // 设置圆环颜色
        mPaint.setStyle(Paint.Style.STROKE);   // 设置空心
        mPaint.setStrokeWidth(mCircleWidth);    // 设置圆环宽度
        mPaint.setAntiAlias(true);             // 消除锯齿
        canvas.drawCircle(centreX, centreX, radius, mPaint);

        // 画进度百分比
        int percent = (int) ((float) mProgress / (float) mMaxProgress * 100); // 进度百分比,需先转为float
        float textWidth;                  // 测量字体宽度,为了设置在圆环中间
        if (!canPress) {
            textWidth = mPaint.measureText(percent + "%");
        } else {
            textWidth = mPaint.measureText(percent * mMaxTime / mMaxProgress + "ms");
        }
        mPaint.setStrokeWidth(0);
        mPaint.setColor(mTextColor);
        mPaint.setTextSize(mTextSize);
        mPaint.setTypeface(Typeface.DEFAULT_BOLD);

        if (isShowText && percent != 0 && mStyle == STROKE) {
            // 如果长按递增,显示时间;否则显示百分比
            if (!canPress) {
                canvas.drawText(percent + "%", centreX - textWidth / 2, centreX + mTextSize / 2, mPaint);
            } else {
                canvas.drawText(percent * mMaxTime / mMaxProgress + "ms", centreX - textWidth / 2, centreX + mTextSize / 2, mPaint);
            }
        }

        // 画圆环的进度
        mPaint.setStrokeWidth(mCircleWidth);
        mPaint.setColor(mCircleProgressColor);
        RectF oval = new RectF(centreX - radius, centreX - radius, centreX + radius, centreX + radius); // 定义边界
        switch (mStyle) {
            case STROKE: {
                mPaint.setStyle(Paint.Style.STROKE);
                canvas.drawArc(oval, 180, 360 * mProgress / mMaxProgress, false, mPaint);
                break;
            }
            case FILL: {
                mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                if (mProgress != 0) {
                    canvas.drawArc(oval, 180, 360 * mProgress / mMaxProgress, true, mPaint);
                }
                break;
            }
        }
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UP:
                if (!isPressing) {
                    return true;
                }
                if (mListener != null) {
                    mListener.onTouchUp();
                }
                stopTime();
                isPressing = false;
                break;
            case MSG_CANCEL:
                if (!isPressing) {
                    return true;
                }
                if (mListener != null) {
                    mListener.onTouchCancel();
                }
                Utils.showToast("cancel");
                mProgress = 0;
                stopTime();
                isPressing = false;
                break;
            case MSG_DOWN:
                isPressing = true;
                if (!canPause) {
                    mProgress = 0;
                }
                // 如果处于暂停状态,继续线程;否则开始线程
                if (canPause && isPause) {
                    isPause = false;
                    mTimeThread.continueThread();
                } else {
                    mTimeThread = new TimeThread();
                    // 是否延时计时
                    if (!isDelay) {
                        mTimeThread.startThread();
                    }
                }
                if (mListener != null) {
                    mListener.onTouchDown();
                }
                break;
        }
        return true;
    }

    /**
     * 计时线程
     */
    public class TimeThread implements Runnable {
        Thread thread;
        int count = mMaxProgress / (mMaxTime / mSleepTime);

        @Override
        public void run() {
            while (isPressing && mProgress <= mMaxProgress) {
                try {
                    Thread.sleep(mSleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 暂停线程
                synchronized (this) {
                    while (isPause || !isPressing) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

                mProgress += count;
                setProgress(mProgress);

            }
        }

        /**
         * 继续线程
         */
        public synchronized void continueThread() {
            notify();
        }

        /**
         * 开始线程
         */
        public void startThread() {
            if (thread == null) {
                thread = new Thread(this);
                thread.start();
            }
        }
    }

    /**
     * 开始计时
     */
    public void startTime() {
        mTimeThread.startThread();
    }

    /**
     * 停止计时
     */
    public void stopTime() {
        isPressing = false;
        if (canPause) {
            isPause = true;
        } else {
            isPause = false;
        }
    }

    public boolean isDelay() {
        return isDelay;
    }

    /**
     * 不开启延时false,按下就开始计时
     * 开启延时true,按下不计时,需调用startTime
     */
    public void setDelay(boolean delay) {
        isDelay = delay;
    }

    public boolean isCanPause() {
        return canPause;
    }

    /**
     *  设置长按后抬起可否暂停,默认不暂停
     */
    public void setCanPause(boolean canPause) {
        this.canPause = canPause;
    }

    public int getMaxTime() {
        return mMaxTime;
    }

    /**
     *  设置最大时间(ms)
     */
    public void setMaxTime(int mMaxTime) {
        this.mMaxTime = mMaxTime;
    }

    public synchronized int getMaxProgress() {
        return mMaxProgress;
    }

    /**
     *  设置最大值
     */
    public synchronized void setMaxProgress(int mMaxProgress) {
        if (mMaxProgress < 0) {
            throw new IllegalArgumentException("最大值不能小于0");
        }
        this.mMaxProgress = mMaxProgress;
    }

    public synchronized int getProgress() {
        return mProgress;
    }

    /**
     *  设置进度, 此为线程安全控件, 考虑多线程问题,需要同步
     *  刷新界面调用postInvalidata(),能在非UI线程刷新
     */
    public synchronized void setProgress(int mProgress) {
        if (mProgress < 0) {
            throw new IllegalArgumentException("进度不能小于0");
        }

        if (mProgress > mMaxProgress) {
            mProgress = mMaxProgress;
            mHandler.sendEmptyMessage(MSG_UP);
        }
        if (mProgress <= mMaxProgress) {
            this.mProgress = mProgress;
            postInvalidate();
        }
    }

    /**
     *  设置触摸事件回调
     */
    public void setOnTouchEventListener(OnTouchEventListener listener) {
        this.mListener = listener;
    }

    public boolean isCanPress() {
        return canPress;
    }

    /**
     * 设置是否可以长按增加进度,默认为不可
     */
    public void setCanPress(boolean canPress) {
        this.canPress = canPress;
    }

    public int getRoundColor() {
        return mCircleColor;
    }

    public void setRoundColor(int mRoundColor) {
        this.mCircleColor = mRoundColor;
    }

    public int getRoundProgressColor() {
        return mCircleProgressColor;
    }

    public void setRoundProgressColor(int mRoundProgressColor) {
        this.mCircleProgressColor = mRoundProgressColor;
    }

    public int getPercentageColor() {
        return mTextColor;
    }

    public void setPercentageColor(int mPercentageColor) {
        this.mTextColor = mPercentageColor;
    }

    public float getPercentageSize() {
        return mTextSize;
    }

    public void setPercentageSize(float mPercentageSize) {
        this.mTextSize = mPercentageSize;
    }

    public float getRoundWidth() {
        return mCircleWidth;
    }

    public void setRoundWidth(float mRoundWidth) {
        this.mCircleWidth = mRoundWidth;
    }

    public boolean isShowText() {
        return isShowText;
    }

    public void setShowText(boolean showText) {
        isShowText = showText;
    }

    public int getStyle() {
        return mStyle;
    }

    /**
     *  0为空心,1为实心
     */
    public void setStyle(int mStyle) {
        this.mStyle = mStyle;
    }


    public interface OnTouchEventListener {
        void onTouchDown();

        void onTouchUp();

        void onTouchCancel();
    }
}
